home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Prog / L-M / mini / VT100.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-09-29  |  27.2 KB  |  1,265 lines  |  [TEXT/MPS ]

  1. /*
  2.     Kermit Vt100 emulator code modified by Jerry LeVan
  3.     to fit the MiniTerm project.
  4.    Date Sept 7,1987
  5.    Changes:    Modified the cursor control routines
  6.                Added Control character Display
  7.             Added Line Drawing Graphics Support
  8. */
  9. /* By Frank on June 20 - Add parity to all outbound chars using software */
  10. /*  Also, ignore DEL (0177) characters on input. */
  11. /* By Bill on May 29 - Add Key set translation */
  12. /* By WBC3 on Apr 24 - Add ^^, ^@ and ^_.  Also use Pascal strings for */
  13. /*  output in the terminal emulator */
  14. /* By WBC3 on Apr 23 - Add query terminal and be more fastidious about */
  15. /*  ignoring sequences we don't know about */
  16. /* By WBC3 on Apr 22 - Fix tab stops to conform to the rest of the world! */
  17. /* By Bill on Apr 21 - Fix immediate echo problems. */
  18. /*  do less cursor_erase, cursor_draw stuff */
  19.  
  20. /*
  21.  * vt100.c
  22.  *
  23.  * Module of MiniTerm: contains most code for the terminal simulation
  24.  * routine.
  25.  */
  26.  
  27. #include <types.h>
  28. #include <Quickdraw.h>
  29. #include <Windows.h>
  30. #include <Fonts.h>
  31. #include <Menus.h>
  32. #include <Events.h>
  33. #include <serial.h>
  34. #include <OSUtils.h>
  35.  
  36. #define tickCount *(long *)0x16a
  37. #define caretTime *(long *)0x2f4
  38.  
  39. #define False         0
  40. #define True         1
  41. #define FALSE         0
  42. #define TRUE         1
  43. #define MAXLIN        24
  44. #define MAXCOL        80
  45. #define LINEHEIGHT  11
  46. #define CHARWIDTH    6
  47. #define TOPMARGIN    3                /* Terminal display constants */
  48. #define BOTTOMMARGIN (LINEHEIGHT * MAXLIN + TOPMARGIN)
  49. #define LEFTMARGIN   3
  50. #define RIGHTMARGIN  (CHARWIDTH * MAXCOL + LEFTMARGIN)
  51. #define LINEADJ         3            /* Amount of char below base line */
  52.  
  53. /* cursor variables */
  54. static char cursorActive;
  55. static Boolean cursorInverted=false ; /* true means inverted pen rect */
  56. static long cursorTime;
  57. static Rect penRect;
  58. static FontInfo fontstuff;
  59. Boolean useBlockCursor = false;
  60. Boolean blink=true;                /* true means blink the cursor */
  61. Boolean invisible = false;
  62.  
  63. /* output character handling */
  64.  
  65. unsigned char obuf[2] = {1,0};        /* single char output buffer */
  66.  
  67. /* Tab settings */
  68.  
  69. #define NUMTABS 9
  70.  
  71. short tabstops[NUMTABS] = {8,16,24,32,40,48,56,64,72};
  72.  
  73. int Invert=FALSE,            /* Flag for Inverted terminal mode */
  74.     insert=FALSE,
  75.     topmargin=TOPMARGIN,        /* Edges of adjustable window */
  76.     bottommargin=BOTTOMMARGIN,
  77.     textstyle=0,
  78.     autowrap=TRUE;            /* Autowrap on by default */
  79.  
  80. char *querystring="\033[?6c";        /* Answer we are a VT102 */
  81.  
  82. short scrollrect[] = { TOPMARGIN, LEFTMARGIN, BOTTOMMARGIN, RIGHTMARGIN };
  83.  
  84. RgnHandle dumptr;                /* Dummy ptr to satisfy scrollbits */
  85.  
  86. /* Screen book keeping variables */
  87.  
  88. char scr[MAXLIN][MAXCOL+1];        /* Characters on the screen */
  89. short nxtlin[MAXLIN], toplin, botlin;    /* Linked list of lines */
  90. int curlin, curcol, abslin;        /* Cursor position */
  91. int savcol, savlin;            /* Cursor save variables */
  92. int scrtop, scrbot;            /* Absolute scrolling region bounds */
  93.  
  94. /* Stuff for escape character processing */
  95.  
  96. #define CF_OUTC 0            /* Just output the char */
  97. #define CF_SESC    1            /* In a single char escape seq */
  98. #define CF_MESC    2            /* In a multi char '[' escape seq */
  99. #define CF_TOSS    3            /* Toss this char */
  100.  
  101. char prvchr, numone[6], numtwo[6], *numptr;
  102. int num1, num2, charflg=CF_OUTC;
  103.  
  104. Boolean use_ascii = true;    /* false means use graphics characters */
  105. Boolean keypad_app = false;    /* false means don't send escape sequences */
  106. extern Boolean interpret_control; /* false means show control character */
  107.  
  108. extern short sOut;    /* refnum of output port */
  109. typedef int (*PFI) ();
  110.  
  111. /* Terminal function declarations. */
  112.  
  113. int tab(), back_space(), carriage_return(), line_feed(), bell(), escape_seq(),
  114.     text_mode(), clear_line(), erase_display(), cursor_position(), cursor_up(),
  115.     cursor_down(), cursor_right(), cursor_left(), cursor_save(),
  116.     cursor_restore(), set_scroll_region(), reverse_line_feed(), dummy(),
  117.     delete_char(), insert_mode(), end_insert_mode(), insert_line(),
  118.     delete_line(), query_terminal(), multi_char(), toss_char(),
  119.     set_ascii(),set_graphics(),set_keypad(),reset_keypad(),cursor_attributes();
  120.  
  121. /* Terminal control character function command table. */
  122.  
  123. #define MINSINGCMDS 000
  124. #define MAXSINGCMDS 037
  125.  
  126. PFI controltable[MAXSINGCMDS-MINSINGCMDS+1] =
  127. {
  128.     dummy,                /*  0 */
  129.     dummy,                /*  1 */
  130.     dummy,                /*  2 */
  131.     dummy,                /*  3 */
  132.     dummy,                /*  4 */
  133.     dummy,                /*  5 */
  134.     dummy,                /*  6 */
  135.     bell,                /*  7 */
  136.     back_space,                /* 10 */
  137.     tab,                /* 11 */
  138.     line_feed,                /* 12 */
  139.     line_feed,                /* 13 (Vertical tab) */
  140.     line_feed,                /* 14 (Form feed) */
  141.     carriage_return,        /* 15 */
  142.     set_graphics,            /* 16 'N'*/
  143.     set_ascii,                /* 17 */
  144.     dummy,                /* 20 */
  145.     dummy,                /* 21 */
  146.     dummy,                /* 22 */
  147.     dummy,                /* 23 */
  148.     dummy,                /* 24 */
  149.     dummy,                /* 25 */
  150.     dummy,                /* 26 */
  151.     dummy,                /* 27 */
  152.     dummy,                /* 30 */
  153.     dummy,                /* 31 */
  154.     dummy,                /* 32 */
  155.     escape_seq,                /* 33 (Escape) */
  156.     dummy,                /* 34 */
  157.     dummy,                /* 35 */
  158.     dummy,                /* 36 */
  159.     dummy                /* 37 */
  160. };
  161.  
  162. #define MINSINGESCS 0040
  163. #define MAXSINGESCS 0137
  164.  
  165. PFI singescapetable[MAXSINGESCS-MINSINGESCS+1] =
  166.     dummy,                /*  40 */
  167.     dummy,                /*  41 */
  168.     dummy,                /*  42 */
  169.     toss_char,                /*  43 '#' */
  170.     dummy,                /*  44 */
  171.     dummy,                /*  45 */
  172.     dummy,                /*  46 */
  173.     dummy,                /*  47 */
  174.     toss_char,                /*  50 '(' */
  175.     toss_char,                /*  51 ')' */
  176.     dummy,                /*  52 */
  177.     dummy,                /*  53 */
  178.     dummy,                /*  54 */
  179.     dummy,                /*  55 */
  180.     dummy,                /*  56 */
  181.     dummy,                /*  57 */
  182.     set_graphics,            /*  60  '0' */
  183.     dummy,                /*  61 */
  184.     dummy,                /*  62 */
  185.     dummy,                /*  63 */
  186.     dummy,                /*  64 */
  187.     dummy,                /*  65 */
  188.     dummy,                /*  66 */
  189.     cursor_save,            /*  67 '7' */
  190.     cursor_restore,            /*  70 '8' */
  191.     dummy,                /*  71 */
  192.     dummy,                /*  72 */
  193.     dummy,                /*  73 */
  194.     dummy,                /*  74 '<' */
  195.     set_keypad,                /*  75 '=' */
  196.     reset_keypad,            /*  76 '>' */
  197.     dummy,                /*  77 */
  198.     dummy,                /* 100 */
  199.     dummy,                /* 101 */
  200.     set_ascii,                /* 102 'B' */
  201.     dummy,                /* 103 */
  202.     line_feed,                /* 104 'D' */
  203.     dummy,                /* 105 'E' */
  204.     dummy,                /* 106 */
  205.     dummy,                /* 107 */
  206.     dummy,                /* 110 */
  207.     dummy,                /* 111 */
  208.     dummy,                /* 112 */
  209.     dummy,                /* 113 */
  210.     dummy,                /* 114 */
  211.     reverse_line_feed,            /* 115 'M' */
  212.     dummy,                /* 116 */
  213.     dummy,                /* 117 */
  214.     dummy,                /* 120 */
  215.     dummy,                /* 121 */
  216.     dummy,                /* 122 */
  217.     dummy,                /* 123 */
  218.     dummy,                /* 124 */
  219.     dummy,                /* 125 */
  220.     dummy,                /* 126 */
  221.     dummy,                /* 127 */
  222.     dummy,                /* 130 */
  223.     dummy,                /* 131 */
  224.     query_terminal,            /* 132 'Z' */
  225.     multi_char,                /* 133 '[' */
  226.     dummy,                /* 134 */
  227.     dummy,                /* 135 */
  228.     dummy,                /* 136 */
  229.     dummy                /* 137 */
  230. };
  231.  
  232. /* Terminal escape sequence function command table */
  233.  
  234. #define MINMULTESCS 0100
  235. #define MAXMULTESCS 0177
  236.  
  237. PFI escapetable[MAXMULTESCS-MINMULTESCS+1] =
  238. {
  239.     dummy,                /* 100 */
  240.     cursor_up,                /* 101 'A' */
  241.     cursor_down,            /* 102 'B' */
  242.     cursor_right,            /* 103 'C' */
  243.     cursor_left,            /* 104 'D' */
  244.     dummy,                /* 105 */
  245.     dummy,                /* 106 */
  246.     dummy,                /* 107 */
  247.     cursor_position,            /* 110 'H' */
  248.     dummy,                /* 111 */
  249.     erase_display,            /* 112 'J' */
  250.     clear_line,                /* 113 'K' */
  251.     insert_line,            /* 114 'L' */
  252.     delete_line,            /* 115 'M' */
  253.     dummy,                /* 116 */
  254.     dummy,                /* 117 */
  255.     delete_char,            /* 120 'P' */
  256.     dummy,                /* 121 */
  257.     dummy,                /* 122 */
  258.     dummy,                /* 123 */
  259.     dummy,                /* 124 */
  260.     dummy,                /* 125 */
  261.     dummy,                /* 126 */
  262.     dummy,                /* 127 */
  263.     dummy,                /* 130 */
  264.     dummy,                /* 131 */
  265.     dummy,                /* 132 */
  266.     dummy,                /* 133 */
  267.     dummy,                /* 134 */
  268.     dummy,                /* 135 */
  269.     dummy,                /* 136 */
  270.     dummy,                /* 137 */
  271.     dummy,                /* 140 */
  272.     dummy,                /* 141 */
  273.     dummy,                /* 142 */
  274.     query_terminal,            /* 143 'c' */
  275.     dummy,                /* 144 */
  276.     dummy,                /* 145 */
  277.     cursor_position,            /* 146 'f' */
  278.     dummy,                /* 147 */
  279.     insert_mode,            /* 150 'h' */
  280.     dummy,                /* 151 */
  281.     dummy,                /* 152 */
  282.     dummy,                /* 153 */
  283.     end_insert_mode,            /* 154 'l' */
  284.     text_mode,                /* 155 'm' */
  285.     dummy,                /* 156 */
  286.     dummy,                /* 157 */
  287.     dummy,                /* 160 */
  288.     dummy,                /* 161 */
  289.     set_scroll_region,            /* 162 'r'*/
  290.     dummy,                /* 163 */
  291.     dummy,                /* 164 */
  292.     dummy,                /* 165 */
  293.     cursor_attributes,                /* 166 'v'*/
  294.     dummy,                /* 167 */
  295.     dummy,                /* 170 */
  296.     dummy,                /* 171 */
  297.     dummy,                /* 172 */
  298.     dummy,                /* 173 */
  299.     dummy,                /* 174 */
  300.     dummy,                /* 175 */
  301.     dummy,                /* 176 */
  302.     dummy                /* 177 */
  303. };
  304. /**********************************************************************/
  305. /*
  306.     The following routine returns true if pacing is turned on and
  307.     the last nonwhite character on the current line is the pacing character
  308. */
  309. Boolean OKToSendChar(theChar,pacing,refNum,inprog)
  310. char theChar;    /* the pacing character */
  311. Boolean pacing; /* true -> do pacing */
  312. short refNum;    /* channel for modem */
  313. Boolean *inprog; /* true means a line is being sent */
  314.  
  315. { short tmp; /* local index */
  316.   SerStaRec statRec;  /* for checking if we are xoff'ed */
  317.  
  318.     SerStatus(refNum,&statRec); /* check modem */
  319.     
  320.     if (statRec.xOffHold)  return false;  /* we are in a xoff state */
  321.     
  322.     if(!pacing) return true;  /* easy case */
  323.     
  324.     if (*inprog) return true; /* a CR will set inprog to false */
  325.     
  326.     for(tmp=0;tmp < curcol;tmp++) /* scan line looking for pace character */
  327.         if (scr[curlin][tmp] == theChar) {
  328.          *inprog = true;  /* starting a new line */
  329.          return true; /* gotit */
  330.         }
  331.     return false; /* nothing was on the line */
  332.     
  333.  }
  334.     
  335. /**********************************************************************/
  336.  
  337. static int strlen(s)
  338. char *s;
  339. { int i;
  340.   i=0;
  341.   while(*s++)i++;
  342.   return i;
  343.  }
  344. /* cursor stuff */
  345. /* for vertical cursor use this */
  346. void oldgetPenRect(r) /* returns address of rect to invert */
  347.   Rect *r;
  348.   { Point pt;  /* for pen cordinates */
  349.     GetPen(&pt);
  350.     r->top = pt.v - fontstuff.ascent;
  351.     r->left = /*(pt.h==LEFTMARGIN)?pt.h-1:*/ pt.h; /* offset one pixel */
  352.     r->bottom = pt.v +fontstuff.descent;
  353.     r->right  = /*(pt.h==LEFTMARGIN)?pt.h:*/ pt.h + 1;   /* skinny */
  354.    }
  355. void getPenRect(r)
  356.   Rect *r;
  357.  { Point pt;
  358.    GetPen(&pt);
  359.    r->top = useBlockCursor ? pt.v - fontstuff.ascent + 1: pt.v;
  360.    r->bottom = pt.v + fontstuff.descent;
  361.    r->left = pt.h;
  362.    r->right = pt.h + fontstuff.widMax ;
  363.   }
  364. void docursor()
  365.    { if(invisible) return;
  366.      if (!blink) return;
  367.      if (cursorActive)
  368.      if(cursorTime < tickCount )
  369.          { cursorTime += caretTime;
  370.             getPenRect(&penRect);
  371.             InvertRect(&penRect);
  372.             cursorInverted = !cursorInverted; /* change state */
  373.           }
  374.     }
  375.     
  376. void start_cursor()
  377.    { if(invisible) return;
  378.      cursorActive = True;
  379.      cursorTime = (tickCount) + (caretTime);
  380. /*     cursorInverted = false; */
  381.      if(!cursorInverted){
  382.      getPenRect(&penRect); InvertRect(&penRect);
  383.      cursorInverted =true;}
  384.     }
  385.     
  386. void stop_cursor()
  387.    { if (invisible) return;
  388.      cursorActive = False;
  389.      if (cursorInverted) {
  390.        getPenRect(&penRect); InvertRect(&penRect);
  391.        cursorInverted =false;
  392.        }
  393.     }
  394.     
  395. /**********************************************************************/
  396.  
  397. /* Connect support routines */
  398.  
  399. InitPage()
  400. {   short theNum;
  401.  
  402.     dumptr = (RgnHandle)NewRgn();
  403.     PenMode(patXor);
  404.     GetFNum("vt100",&theNum);
  405.     if(theNum)
  406.         TextFont(theNum);  /* keep it simple */
  407.     else TextFont(monaco);
  408.     TextSize(9);
  409.     GetFontInfo(&fontstuff);
  410.     init_term();            /* Set up some terminal variables */
  411.     clear_screen();            /* Clear the screen */
  412.     home_cursor();            /* Go to the upper left */
  413.     cursor_save();            /* Save this position */
  414.     cursorInverted = false;
  415.     start_cursor();
  416. }
  417.  
  418.  
  419.  
  420. /* writeps - write a pascal form string to the serial port.
  421.  *
  422.  */
  423.  
  424. writeps(s)
  425. char *s;
  426. {
  427.   long wcnt, w2;
  428.   int err; char *s2;
  429.  
  430.   w2 = wcnt = *s++;            /* get count */
  431.   err = FSWrite(sOut,&wcnt,s);    /* write the characters */
  432.   return;
  433. }
  434.  
  435. /* getindstr - given an indirect (or is it indexed) string and integer
  436.  *               n, return the pointer to the Nth substring.
  437.  *
  438.  * Indirect strings have the count of substrings in the first byte and
  439.  * each string follows with a length byte and a body.
  440.  *
  441.  * Substrings are referenced by 1..N
  442.  *
  443.  */
  444.  
  445. char *getindstr(indstr,n)
  446. char *indstr;
  447. {
  448.   register char *ip = indstr;
  449.   int i;
  450.  
  451.   if (n > *ip++)            /* too large? */
  452.    return("");                /* yes, return empty pascal string */
  453.  
  454.   for (i=1; i < n; i++)            /* scan until we hit the Nth */
  455.    ip += (*ip)+1;            /* move to next substring */
  456.  
  457.   return(ip);                /* return ptr to it */
  458. }
  459.  
  460.  
  461. char outbuf[MAXCOL+1];
  462. int outcnt=0, outcol;
  463.  
  464. flushbuf()
  465. {
  466.     Rect r;
  467.     Boolean cursorWasActive;
  468.  
  469.     if (outcnt == 0) return;        /* Nothing to flush */
  470.     
  471.     if(cursorWasActive = cursorActive) stop_cursor();
  472.  
  473. /* Erase a hole large enough for outcnt chars */
  474.  
  475.     makerect(&r,abslin,outcol,1,outcnt);
  476.  
  477.     if (Invert) FillRect(&r,qd.black);
  478.     else EraseRect(&r);
  479.  
  480.     outbuf[outcnt] = '\0';        /* Terminate the string */
  481.     DrawString(outbuf);            /* Output the string */
  482.     if(cursorWasActive)start_cursor();
  483.     outcnt = 0;                /* Say no more chars to output */
  484. }
  485.  
  486. buf_char(c)
  487. char c;
  488. {
  489.     if (outcnt == 0) outcol = curcol;    /* No chars in buffer, init column */
  490.     if(outcnt == MAXCOL){ SysBeep(3); return; } /* don't overflow buffer */
  491.     outbuf[outcnt++] = c;        /* Put in the buffer to output later */
  492. }
  493.  
  494. /*
  495.  *  put_ch:
  496.  *    Draws character and updates buffer
  497.  */
  498.     
  499. void Put_Char(c)
  500. char c;
  501. {
  502.     PFI funp, lookup();
  503.  
  504.     c &= 0177;
  505.     stop_cursor();
  506.     switch (charflg)
  507.     {
  508.     case CF_OUTC:            /* Just output the char */
  509.         drawAChar(c);
  510.         break;
  511.  
  512.     case CF_SESC:            /* In a single char escape seq */
  513.         if(c == '(') break;    /* wait for '0' or 'B' */
  514.         charflg = CF_OUTC;        /* Reset flag to simple outputting */
  515.         if(funp=lookup(c,singescapetable,MINSINGESCS,MAXSINGESCS))
  516.             (*funp)();        /* Do escape sequence function */
  517.         break;
  518.  
  519.     case CF_MESC:            /* Multichar escape sequence */
  520.         if (c >= 0x20 && c < 0x40)  /* Deal with the modifiers */
  521.         {
  522.         if (c >= '<' && c <= '?') prvchr = c;   /* Handle priv char */
  523.         else if ((c >= '0' && c <= '9') || c == '-' || c == '+')
  524.         {
  525.             *numptr++ = c;    /* Add the char to the num */
  526.             *numptr = '\0';    /* Terminate the string */
  527.         }
  528.         else if (c == ';') numptr = numtwo;    /* Go to next number */
  529.         }
  530.         else            /* End of sequence */
  531.         {
  532.         if (funp=lookup(c,escapetable,MINMULTESCS,MAXMULTESCS))
  533.         {
  534.             StringToNum(numone,&num1); /* Translate the numbers */
  535.             StringToNum(numtwo,&num2);
  536.             (*funp)();        /* Do the escape sequence function */
  537.         }
  538.         charflg = CF_OUTC;    /* Back to simple outputting */
  539.         }
  540.         break;
  541.  
  542.     case CF_TOSS:            /* Ignore this char */
  543.         charflg = CF_OUTC;        /* Reset flag */
  544.         break;
  545.     }
  546.     start_cursor();
  547. }
  548.  
  549. /*
  550.  * Routine makerect
  551.  *
  552.  * Make a rectangle in r starting on line lin and column col extending
  553.  * numlin lines and numcol characters.
  554.  *
  555.  */
  556.  
  557. makerect(r,lin,col,numlin,numcol)
  558. Rect *r;
  559. int lin, col, numlin, numcol;
  560. {
  561.     r->top = lin * LINEHEIGHT + TOPMARGIN;
  562.     r->left = col * CHARWIDTH + LEFTMARGIN;
  563.     r->bottom = r->top + numlin * LINEHEIGHT;
  564.     r->right = r->left + numcol * CHARWIDTH;
  565. }
  566.  
  567. /*
  568.  *   Lookup:
  569.  *    Lookup a given character in the apropriate character table, and
  570.  *    return a pointer to the appropriate function, if it exists.
  571.  */
  572.  
  573. PFI
  574. lookup(index,table,min,max)
  575. char index;
  576. PFI table[];
  577. int min, max;
  578. {
  579.     if (index > max || index < min)
  580.         return((PFI) NULL);            /* Don't index out of range */
  581.     return(table[index-min]);
  582. }
  583.  
  584.  
  585. /*
  586.  *   Flushio:
  587.  *    Initialize some communications constants, and clear screen and
  588.  *    character buffers.
  589.  */
  590.  
  591. flushio()
  592. {
  593. }    
  594.  
  595.    
  596. /* sendbreak - sends a break across the communictions line.
  597.  *
  598.  * The argument is in units of approximately 0.05 seconds (or 50
  599.  * milliseconds).  To send a break of duration 250 milliseconds the
  600.  * argument would be 5; a break of duration 3.5 seconds would be (umm,
  601.  * lets see now) 70.
  602.  *
  603.  */
  604.  
  605. sendbreak(msunit)
  606.     int finalticks;
  607.  
  608.  
  609. }
  610.      
  611. drawAChar(chr)
  612. unsigned char chr;
  613. {
  614.     PFI funp;
  615.     Boolean cursorWasActive;
  616.  
  617.     if(cursorWasActive = cursorActive)stop_cursor();
  618.     
  619. /* If it's a control char, do the apropriate function. */
  620.     if ((chr < (unsigned char)' ') && interpret_control)        /* Is it a control character */
  621.     {     
  622.     flushbuf();
  623.     if (funp=lookup(chr,controltable,MINSINGCMDS,MAXSINGCMDS)) (*funp)();
  624.     }
  625.     else if (chr < (unsigned char)0177)              /* Handle graphic characters */
  626.     {
  627.     if(!use_ascii)
  628.       if((chr >= (unsigned char)0137) && (chr <= (unsigned char)0176)) /* if in graphics mode */
  629.          chr += 0200;            /* offset to high ascii */
  630.          
  631.      if (chr < (unsigned char)0040)            /* if a control char */
  632.         if(!interpret_control) chr += 0200;
  633.         
  634.     if (curcol >= MAXCOL)        /* Are we about to wrap around? */
  635.     {
  636.         if (autowrap)        /* If autowrap indicated wrap */
  637.         {
  638.         flushbuf();
  639.         carriage_return();
  640.         line_feed();
  641.         }
  642.         else
  643.         {
  644.         back_space();        /* Otherwise just overwrite */
  645.         outcnt--;        /* Overwrite buffered chars too */
  646.         }
  647.     }
  648.     if (insert)            /* Insert mode? */
  649.     {
  650.         insert_char();        /* Open hole for char if requested */
  651.         erase_char();        /* Erase the old char */
  652.         DrawChar(chr);
  653.     }
  654.     else buf_char(chr);        /* Otherwise just buffer the char */
  655.     scr[curlin][curcol++] = chr;
  656.     }
  657.   if(cursorWasActive)start_cursor();
  658. }    
  659.  
  660. void drawCString(strptr)
  661.      char * strptr;
  662.      { char ch;
  663.        while(ch=*strptr++)drawAChar(ch);
  664.       }
  665.  
  666. void drawPString(strptr)
  667.      char *strptr;
  668.      { short i;
  669.        for(i=1;i<=strptr[0];i++)drawAChar(strptr[i]);
  670.       }
  671.       
  672.  
  673. /*
  674.  *    Control character functions:
  675.  *        Each of the following allow the mac to simulate
  676.  *        the behavior of a terminal when given the proper
  677.  *        control character.
  678.  */
  679.  
  680. back_space()
  681. {
  682.     if (curcol > 0) relmove(-1,0);
  683. }
  684.  
  685. erase_char()
  686. {
  687.     Rect r;
  688.  
  689.     scr[curlin][curcol] = ' ';        /* Erase char for update */
  690.     makerect(&r,abslin,curcol,1,1);    /* One char by one line */
  691.  
  692.     if (Invert) FillRect(&r,qd.black);
  693.     else EraseRect(&r);
  694. }
  695.  
  696. tab()
  697. {
  698.     int i;
  699.  
  700.     for (i=0; i<NUMTABS; i++)
  701.     {
  702.         if (tabstops[i] > curcol)
  703.     {
  704.         absmove(tabstops[i],abslin);
  705.         return;
  706.     }
  707.     }
  708. }
  709.  
  710. line_feed()
  711. {
  712.     int tbot, ttop, tlout;
  713.  
  714.     if (curlin == scrbot)
  715.     {
  716.     ScrollRect((Rect *) scrollrect,0,-LINEHEIGHT,dumptr);
  717.     SetEmptyRgn(dumptr);
  718.     zeroline(scrtop);
  719.     tbot = scrbot;
  720.     ttop = scrtop;
  721.     tlout = nxtlin[scrbot];
  722.     nxtlin[scrbot] = scrtop;
  723.     scrbot = scrtop;
  724.     scrtop = nxtlin[scrtop];
  725.     if (ttop == toplin) toplin = scrtop;
  726.         else nxtlin[fndprv(ttop)] = scrtop;
  727.     if (tbot == botlin)
  728.     {
  729.         botlin = scrbot;
  730.         nxtlin[botlin] = -1;
  731.     }
  732.     else nxtlin[scrbot] = tlout;
  733.     curlin = scrbot;
  734.     }
  735.     else relmove(0,1);
  736. }
  737.  
  738. reverse_line_feed()
  739. {
  740.     int tbot, ttop, tlout;
  741.  
  742.     if (curlin == scrtop)
  743.     {
  744.     ScrollRect((Rect *) scrollrect,0,LINEHEIGHT,dumptr);
  745.     SetEmptyRgn(dumptr);
  746.     zeroline(scrbot);
  747.     tbot = scrbot;
  748.     ttop = scrtop;
  749.     tlout = nxtlin[scrbot];
  750.     nxtlin[scrbot] = scrtop;
  751.     scrtop = scrbot;
  752.     scrbot = fndprv(scrbot);
  753.     if (ttop == toplin) toplin = scrtop;
  754.         else nxtlin[fndprv(ttop)] = scrtop;
  755.     if (tbot == botlin)
  756.     {
  757.         botlin = scrbot;
  758.         nxtlin[botlin] = -1;
  759.     }
  760.     else nxtlin[scrbot] = tlout;
  761.     curlin = scrtop;
  762.     }
  763.     else relmove(0,-1);
  764. }
  765.  
  766. carriage_return()
  767. {
  768.     absmove(0,abslin);
  769. }
  770.  
  771. clear_screen()
  772. {
  773.     register int i;
  774.     Rect r;
  775.     GrafPtr thisPortptr;
  776.  
  777. /*
  778.     makerect(&r,0,0,MAXLIN,MAXCOL);    
  779.     EraseRect(&r);
  780. */
  781.     GetPort(&thisPortptr);
  782.     EraseRect(&thisPortptr->portRect);
  783.     
  784.     for (i=0; i<MAXLIN; i++) zeroline(i);   /* Clear up the update records */
  785. }
  786.  
  787. home_cursor()
  788. {
  789.     absmove(0,0);
  790. }
  791.  
  792. bell()
  793. {
  794.     SysBeep(3);
  795. }
  796.  
  797. escape_seq()
  798. {
  799.     charflg = CF_SESC;            /* Say we are in an escape sequence */
  800. }
  801.  
  802. clear_line()
  803. {
  804.     int i;
  805.     Rect r;
  806.  
  807.     switch (num1)
  808.     {
  809.     case 0:                /* Clear:  here to the right */
  810.         makerect(&r,abslin,curcol,1,MAXCOL-curcol);
  811.         for (i=curcol; i<MAXCOL; i++) scr[curlin][i] = ' ';
  812.         break;
  813.  
  814.     case 1:                /* Clear:  left to here */
  815.         makerect(&r,abslin,0,1,curcol+1);
  816.         for (i=0; i<=curcol; i++) scr[curlin][i] = ' ';
  817.         break;
  818.  
  819.     case 2:                /* Clear:  entire line */
  820.         makerect(&r,abslin,0,1,MAXCOL);
  821.         zeroline(curlin);
  822.         break;
  823.     }
  824.     EraseRect(&r);
  825. }
  826.  
  827. erase_display()
  828. {
  829.     int i;
  830.     Rect r;
  831.  
  832.     switch (num1)
  833.     {
  834.     case 0:
  835.         clear_line();        /* Same num1 causes correct clear */
  836.         makerect(&r,abslin+1,0,MAXLIN-abslin,MAXCOL);
  837.         EraseRect(&r);
  838.         for (i=abslin+1; i<MAXLIN; i++) zeroline(fndrel(i));
  839.         break;
  840.  
  841.     case 1:
  842.         clear_line();        /* Same num1 causes correct clear */
  843.         makerect(&r,0,0,abslin,MAXCOL);
  844.         EraseRect(&r);
  845.         for (i=0; i<abslin; i++) zeroline(fndrel(i));
  846.         break;
  847.  
  848.     case 2:
  849.         clear_screen();
  850.         break;
  851.     }
  852. }
  853.             
  854. /**** All cursor moves need to check that they don't go beyond the margins */
  855.  
  856. cursor_right()
  857. {
  858.     if (num1 == 0) num1 = 1;
  859.     relmove(num1,0);
  860. }
  861.  
  862. cursor_left()
  863. {
  864.     if (num1 == 0) num1 = 1;
  865.     relmove(-num1,0);
  866. }
  867.  
  868. cursor_up()
  869. {
  870.     if (num1 == 0) num1 = 1;
  871.     relmove(0,-num1);
  872. }
  873.  
  874. cursor_down()
  875. {
  876.     if (num1 == 0) num1 = 1;
  877.     relmove(0,num1);
  878. }
  879.  
  880. cursor_position()
  881. {
  882.     if (--num1 < 0) num1 = 0;
  883.     if (--num2 < 0) num2 = 0;
  884.  
  885.     absmove(num2,num1);
  886. }
  887.  
  888. cursor_save()
  889. {
  890.     savcol = curcol;            /* Save the current line and column */
  891.     savlin = abslin;
  892. }
  893.  
  894. cursor_restore()
  895. {
  896.     absmove(savcol,savlin);        /* Move to the old cursor position */
  897. }
  898.  
  899. cursor_draw()
  900. {
  901.     Line(CHARWIDTH,0);            /* Draw cursor */
  902. }
  903.  
  904. cursor_erase()
  905. {
  906.     Line(-CHARWIDTH,0);            /* Erase cursor */
  907. }
  908.  
  909. set_scroll_region()
  910. {
  911.     if (--num1 < 0) num1 = 0;        /* Make top of line (prev line) */
  912.     if (num2 == 0) num2 = 24;        /* Zero means entire screen */
  913.  
  914.     topmargin = scrollrect[0] = (num1 * LINEHEIGHT) + TOPMARGIN;
  915.     bottommargin = scrollrect[2] = (num2 * LINEHEIGHT) + TOPMARGIN;
  916.  
  917.     scrtop = fndrel(num1);
  918.     scrbot = fndrel(num2-1);
  919.  
  920.     home_cursor();            /* We're supposed to home it! */
  921. }
  922.  
  923.  
  924. text_mode()                /**** */
  925. {
  926.     switch(num1)
  927.     {
  928.     case 0: 
  929.         Invert=FALSE;
  930.         textstyle=0;
  931.         TextFace(0);
  932.         TextMode(srcOr);
  933.         TextSize(9);
  934.         break;
  935.  
  936.     case 1:
  937.         textstyle +=bold;
  938.         TextFace(textstyle);
  939.         TextSize(8);    /* shrink a little */
  940.         break;
  941.  
  942.     case 4:
  943.         textstyle+=underline;
  944.         TextFace(textstyle);
  945.         TextSize(9);
  946.         break;
  947.  
  948.     case 7:
  949.         Invert=TRUE;
  950.         TextMode(srcBic);
  951.         TextSize(9);
  952.         break;
  953.  
  954.     case 22:
  955.         if (textstyle >= bold)
  956.         {
  957.         TextFace(textstyle-bold);
  958.         textstyle -= bold;
  959.         }
  960.         break;
  961.  
  962.     case 24:
  963.         if (textstyle >= underline)
  964.         {
  965.         TextFace(textstyle-underline);
  966.         textstyle -= underline;
  967.         }
  968.         break;
  969.  
  970.     case 27:
  971.         Invert = FALSE;
  972.         TextMode(srcOr);
  973.         break;
  974.     }
  975. }    
  976.  
  977. /**** NYI */
  978. insert_line()
  979. {
  980.     Rect r;
  981.  
  982.     if (num1 == 0) num1 = 1;
  983.  
  984.     makerect(&r,abslin,0,0,MAXCOL);
  985.     r.bottom = bottommargin;        /* Just do this for now */
  986.  
  987.     if (num1 > fndabs(scrbot) - abslin)
  988.         num1 = fndabs(scrbot) - abslin;
  989.  
  990.     ScrollRect(&r,0,num1*LINEHEIGHT,dumptr);
  991.     SetEmptyRgn(dumptr);
  992. /* Do the book keeping!!! */
  993. }
  994.  
  995. delete_line()
  996. {
  997.     Rect r;
  998.  
  999.     if (num1 == 0) num1 = 1;
  1000.  
  1001.     makerect(&r,abslin,0,0,MAXCOL);
  1002.     r.bottom = bottommargin;        /* Just do this for now */
  1003.  
  1004.     if (num1 > fndabs(scrbot) - abslin)
  1005.         num1 = fndabs(scrbot) - abslin;
  1006.  
  1007.     ScrollRect(&r,0,-num1*LINEHEIGHT,dumptr);
  1008.     SetEmptyRgn(dumptr);
  1009. /* Do the book keeping!!! */
  1010. }
  1011.  
  1012. delete_char()
  1013. {
  1014.     int i;
  1015.     Rect r;
  1016.  
  1017.     if (num1 == 0) num1 = 1;
  1018.  
  1019.     makerect(&r,abslin,curcol,1,MAXCOL-curcol);
  1020.  
  1021.     if(num1 > MAXCOL - curcol - 1) num1 = MAXCOL - curcol - 1;
  1022.  
  1023.     ScrollRect(&r,-CHARWIDTH*num1,0,dumptr);  /* Scroll em out */
  1024.     SetEmptyRgn(dumptr);
  1025.  
  1026. /* Shift em down */
  1027.  
  1028.     for (i=curcol; i<MAXCOL-num1; i++) scr[abslin][i] = scr[abslin][i+num1];
  1029.     while (i < MAXCOL) scr[abslin][i++] = ' ';    /* Fill in holes with spaces */
  1030. }
  1031.  
  1032. insert_char()
  1033. {
  1034.     int i;
  1035.     Rect r;
  1036.  
  1037.     makerect(&r,abslin,curcol,1,MAXCOL-curcol);
  1038.  
  1039.     ScrollRect(&r,CHARWIDTH,0,dumptr);
  1040.     SetEmptyRgn(dumptr);
  1041.  
  1042. /* Shift em up */
  1043.  
  1044.     for (i=MAXCOL-1; i>curcol+1; i--) scr[abslin][i-1] = scr[abslin][i];
  1045.     scr[abslin][curcol] = ' ';
  1046. }
  1047.  
  1048. insert_mode()
  1049. {
  1050.     if (prvchr == '?') return;        /* Don't deal with these calls */
  1051.     if (num1 == 4) insert = TRUE;
  1052. }
  1053.  
  1054. end_insert_mode()
  1055. {
  1056.     if (prvchr == '?') return;        /* Don't deal with these calls */
  1057.     if (num1 == 4) insert = FALSE;
  1058. }
  1059.  
  1060. query_terminal()
  1061. {
  1062.     long wrcnt, w2;
  1063.     int err; char *s2;
  1064.  
  1065.     w2 = wrcnt = strlen(querystring);    /* How long is the string? */
  1066.     err = FSWrite(sOut,&wrcnt,querystring);    /* Respond to the query */
  1067. }
  1068.  
  1069. dummy()
  1070. {
  1071. }
  1072.  
  1073. multi_char()
  1074. {
  1075.     numone[0] = numtwo[0] = '0';    /* Initialize the numbers to zero */
  1076.     numone[1] = numtwo[1] = '\0';
  1077.     numptr = numone;            /* Place to put the next number */
  1078.     prvchr = '\0';            /* No priv char yet */
  1079.     charflg = CF_MESC;            /* Say we are in a ESC [ swequence */
  1080. }
  1081.  
  1082. toss_char()
  1083. {
  1084.     charflg = CF_TOSS;
  1085. }
  1086.  
  1087. /*
  1088.  * Routine zeroline
  1089.  *
  1090.  * Zero (set to space) all the characters in relative line lin.
  1091.  *
  1092.  */
  1093.  
  1094. zeroline(lin)
  1095. int lin;
  1096. {
  1097.     register int i;
  1098.  
  1099.     for (i=0; i<MAXCOL; i++) scr[lin][i] = ' ';
  1100. }
  1101.  
  1102. /*
  1103.  * Move a relative number of lines and chars.  Both can be negative.
  1104.  *
  1105.  */
  1106.  
  1107. relmove(hor,ver)
  1108. {
  1109.     Move(hor*CHARWIDTH,ver*LINEHEIGHT);
  1110.     curcol += hor;
  1111.     abslin += ver;
  1112.     curlin = fndrel(abslin);
  1113. }
  1114.  
  1115. /*
  1116.  * Move to absolute position hor char and ver line.
  1117.  *
  1118.  */
  1119.  
  1120. absmove(hor,ver)
  1121. {
  1122.     MoveTo(hor*CHARWIDTH+LEFTMARGIN,(ver+1)*LINEHEIGHT+TOPMARGIN-LINEADJ);
  1123.     curcol = hor;
  1124.     abslin = ver;
  1125.     curlin = fndrel(ver);
  1126. }
  1127.  
  1128. /*
  1129.  * Find the relative line number given the absolute one.
  1130.  *
  1131.  */
  1132.  
  1133. fndrel(linum)
  1134. int linum;
  1135. {
  1136.     register int i, lin;
  1137.  
  1138.     lin = toplin;
  1139.     for (i=0; i<linum; i++) lin = nxtlin[lin];
  1140.     return(lin);
  1141. }
  1142.  
  1143. /*
  1144.  * Find the absolute line number given the relative one.
  1145.  *
  1146.  */
  1147.  
  1148. fndabs(linum)
  1149. int linum;
  1150. {
  1151.     int i, lin;
  1152.  
  1153.     lin = toplin;
  1154.     i = 0;
  1155.     while (lin != linum)
  1156.     {
  1157.     i++;
  1158.     lin = nxtlin[lin];
  1159.     }
  1160.     return(i);
  1161. }
  1162.  
  1163. /*
  1164.  * Find the previous relative line number from relative line linum.
  1165.  *
  1166.  */
  1167.  
  1168. fndprv(linum)
  1169. int linum;
  1170. {
  1171.     int lin;
  1172.  
  1173.     lin = toplin;
  1174.     while (nxtlin[lin] != linum) lin = nxtlin[lin];
  1175.     return(lin);
  1176. }
  1177.  
  1178. term_redraw()
  1179. {
  1180.     int i, lin;
  1181.  
  1182.     lin = toplin;
  1183.     for (i=0; i<MAXLIN; i++)
  1184.     {
  1185.     MoveTo(LEFTMARGIN,(i+1)*LINEHEIGHT+TOPMARGIN-LINEADJ);
  1186.     DrawString(scr[lin]);
  1187.     lin = nxtlin[lin];
  1188.     }
  1189.     MoveTo(curcol*CHARWIDTH+LEFTMARGIN,
  1190.         (abslin+1)*LINEHEIGHT+TOPMARGIN-LINEADJ);
  1191. }
  1192.  
  1193. init_term()
  1194. {
  1195.     int i;
  1196.  
  1197.     for (i=0; i<MAXLIN; i++)
  1198.     {
  1199.     nxtlin[i] = i + 1;        /* Tie together the linked list */
  1200.     scr[i][MAXCOL] = '\0';        /* Terminate the lines as strings */
  1201.     }
  1202.     toplin = 0;                /* Initialize the top and bottom ptr */
  1203.     botlin = MAXLIN - 1;
  1204.     scrtop = toplin;            /* Scrolling region equals all */
  1205.     scrbot = botlin;
  1206.     nxtlin[botlin] = -1;        /* Indicate this is the end */
  1207. }
  1208.  
  1209. reset_term()
  1210. {
  1211.     stop_cursor();            /* take cursor off */
  1212.     clear_screen();
  1213.     home_cursor();
  1214.     cursor_save();
  1215.     
  1216.     Invert=FALSE;
  1217.     textstyle=0;
  1218.     TextFace(0);
  1219.     TextMode(srcOr);
  1220.     TextSize(9);
  1221.     
  1222.     use_ascii = true;    /* false means use graphics characters */
  1223.     keypad_app = false;    /* false means don't send escape sequences */
  1224.     init_term();
  1225.     start_cursor();
  1226.     SysBeep(10);
  1227.  }
  1228. /* 
  1229.  *    Support for different cursor attributes
  1230.  */
  1231. cursor_attributes()
  1232. { stop_cursor();
  1233.   switch(num1){
  1234.   case 0: invisible =false;
  1235.             break;
  1236.   case 1: invisible = true;
  1237.               break;
  1238.   case 2: useBlockCursor = false;  /* use underline */
  1239.               break;
  1240.   case 3: useBlockCursor = true;        /* use block */
  1241.               break;
  1242.   case 4: blink = false;    /* don't blink */
  1243.               break;
  1244.   case 5: blink = true;
  1245.               break;
  1246.  }
  1247.  start_cursor();
  1248.  }
  1249. /*
  1250.     Support for change keypad mode and alternate character set
  1251. */
  1252.  
  1253. set_ascii()
  1254. { use_ascii = true;}
  1255.  
  1256. set_graphics()
  1257.  { use_ascii = false; }
  1258.  
  1259. set_keypad()
  1260.   { keypad_app = true; }
  1261.   
  1262. reset_keypad()
  1263.    { keypad_app = false; }